package com.wish.nettyprotobuf;

import com.wish.common.MyUtils;

import com.wish.protobuf.ProtobufUser;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;


/**
 * @author tantexian
 * @since 2016/7/11
 */
public class NettyProtobufClient {

    public static void main(String[] args) {
        new NettyProtobufClient().connect(MyUtils.getDefaultServerAddr(), MyUtils.getDefaultPort());
    }


    public void connect(String host, int port) {
        // 关于使用方式请参考NettyRobotServer注释
        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        try {
            bootstrap.group(eventLoopGroup).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true).handler(new ChannelInitializer<SocketChannel>() {
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline pipeline = socketChannel.pipeline();

                    // 此处用来处理server返回的String 类型的msg给client（此类编解码需要放置在前面）
                    pipeline.addLast(new StringDecoder());
                    pipeline.addLast(new StringEncoder());
                    pipeline.addLast(new LineBasedFrameDecoder(1024));

                    // 对protobuf协议的的消息头上加上一个长度为32的整形字段，用于标志这个消息的长度。
                    // 用于半包处理
                    pipeline.addLast(new ProtobufVarint32FrameDecoder());
                    // 添加protobuf解码器
                    pipeline.addLast(new ProtobufDecoder(ProtobufUser.User.getDefaultInstance()));
                    pipeline.addLast(new ProtobufVarint32LengthFieldPrepender());
                    // 添加protobuf编码器
                    pipeline.addLast(new ProtobufEncoder());
                    pipeline.addLast(new ProtobufClientHandle());
                }
            });

            ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            eventLoopGroup.shutdownGracefully();
        }
    }

    class ProtobufClientHandle extends ChannelHandlerAdapter {

        private ByteBuf sendMsgBuffer;


        ProtobufClientHandle() {
        }


        public ProtobufUser.User createUser(int i) {
            ProtobufUser.User.Builder builder = ProtobufUser.User.newBuilder();
            builder.setId(i);
            builder.setUserName("tantexian-" + i);
            builder.setAddress("I'm chengdu " + i);
            ProtobufUser.User user = builder.build();
            return user;

        }


        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            for (int i = 0; i < 10; i++) {
                ctx.write(createUser(i));
            }
            ctx.flush();
        }


        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            System.out.println("The NettyProtobufClient receive msg: " + msg);
        }


        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }

}
